package lol.clann.bukkit.pluginboot.context;

import lol.clann.bukkit.pluginboot.service.ExecutorService;
import lol.clann.bukkit.pluginboot.service.PatternTimerExecutor;
import lol.clann.bukkit.pluginboot.task.BukkitTimer;
import lol.clann.bukkit.pluginboot.task.PatternTimer;
import lol.clann.bukkit.pluginboot.task.Task;
import lol.clann.bukkit.pluginboot.task.Timer;
import lol.clann.clannboot.annotation.load.PostLoad;
import lol.clann.clannboot.annotation.load.Unload;
import lol.clann.clannboot.annotation.svc.PreInstance;
import lol.clann.clannboot.context.BeanContext;
import lol.clann.clannboot.context.InitialStageCallback;
import lol.clann.clannboot.context.InitialStageCallbackContext;
import lol.clann.clannboot.context.ModuleContext;
import lol.clann.clannboot.model.LazyLoadLogger;
import lol.clann.clannboot.util.clazz.ClassUtils;
import lol.clann.clannboot.util.clazz.WrapClass;
import lol.clann.clannboot.util.clazz.WrapMethod;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.PluginMessageListener;

import java.util.Collection;

/**
 * @author pyz
 * @date 2018/9/16 下午5:50
 */
public class InitialStageCallbackRegister {

    private static final LazyLoadLogger logger = new LazyLoadLogger(ModuleContext.rootModuleId);
    private static boolean pluginRegister = false;

    static {
        InitialStageCallback callback = null;

        // 注册所有插件实例到beancontext
        callback = new InitialStageCallback(holder -> {
            if (isPluginRegister()) {
                // 这个只能执行一次
                return;
            }
            setPluginRegister(true);
            for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
                BeanContext.registerBean(ModuleContext.rootModuleId, plugin.getClass().getName(), plugin);
            }
        }, null);
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PreInstance.class, callback);


        // 监听器
        callback = new InitialStageCallback(null, holder -> {
            if (Listener.class.isAssignableFrom(holder.getServiceClass())) {
                Bukkit.getPluginManager().registerEvents((Listener) holder.getHandle(), holder.getModule().getExtend());
                holder.getModule().getLogger().info("注册监听器:" + holder.getId());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);

        // 注销监听器
        callback = new InitialStageCallback(null, holder -> {
            if (Listener.class.isAssignableFrom(holder.getServiceClass())) {
                HandlerList.unregisterAll((Listener) holder.getHandle());
                holder.getModule().getLogger().info("注销监听器:" + holder.getId());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, Unload.class, callback);

        // 消息监听器
        callback = new InitialStageCallback(null, holder -> {
            if (PluginMessageListener.class.isAssignableFrom(holder.getServiceClass())) {
                String[] args = holder.getArgs();
                Bukkit.getMessenger().registerIncomingPluginChannel(holder.getModule().getExtend(), args[0], (PluginMessageListener) holder.getHandle());
                Bukkit.getMessenger().registerOutgoingPluginChannel(holder.getModule().getExtend(), args[0]);
                holder.getModule().getLogger().info("注册消息监听器:" + holder.getId());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);

        // 注销消息监听器
        callback = new InitialStageCallback(null, holder -> {
            if (PluginMessageListener.class.isAssignableFrom(holder.getServiceClass())) {
                String[] args = holder.getArgs();
                Bukkit.getMessenger().unregisterIncomingPluginChannel(holder.getModule().getExtend(), args[0], (PluginMessageListener) holder.getHandle());
                Bukkit.getMessenger().unregisterOutgoingPluginChannel(holder.getModule().getExtend(), args[0]);
                holder.getModule().getLogger().info("注销消息监听器:" + holder.getId());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, Unload.class, callback);

        // Task
        callback = new InitialStageCallback(null, holder -> {
            WrapClass wrapClass = ClassUtils.wrap(holder.getServiceClass());
            Collection<WrapMethod> ms = wrapClass.getAnnotionMethod(Task.class).values();
            for (WrapMethod wm : ms) {
                Task config = wm.getAnnotation(Task.class);
                ExecutorService.task(holder.getModule().getId(), config, () -> wm.invoke(holder.getHandle()));
                holder.getModule().getLogger().info("start task:" + config.toString());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);

        // Timer
        callback = new InitialStageCallback(null, holder -> {
            WrapClass wrapClass = ClassUtils.wrap(holder.getServiceClass());
            Collection<WrapMethod> ms = wrapClass.getAnnotionMethod(Timer.class).values();
            for (WrapMethod wm : ms) {
                Timer config = wm.getAnnotation(Timer.class);
                ExecutorService.timer(holder.getModule().getId(), config, () -> wm.invoke(holder.getHandle()));
                holder.getModule().getLogger().info("start timer:" + config.toString());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);

        // PatternTimer
        callback = new InitialStageCallback(null, holder -> {
            WrapClass wrapClass = ClassUtils.wrap(holder.getServiceClass());
            Collection<WrapMethod> ms = wrapClass.getAnnotionMethod(PatternTimer.class).values();
            for (WrapMethod wm : ms) {
                PatternTimer config = wm.getAnnotation(PatternTimer.class);
                PatternTimerExecutor.addTask(holder.getModule().getId(), config, () -> wm.invoke(holder.getHandle()));
                holder.getModule().getLogger().info("start patternTimer:" + config.toString());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);

        //BukkitTimer
        callback = new InitialStageCallback(null, holder -> {
            WrapClass wrapClass = ClassUtils.wrap(holder.getServiceClass());
            Collection<WrapMethod> ms = wrapClass.getAnnotionMethod(BukkitTimer.class).values();
            for (WrapMethod wm : ms) {
                BukkitTimer config = wm.getAnnotation(BukkitTimer.class);
                ExecutorService.bukkitTimer(holder.getModule().getId(), config, () -> wm.invoke(holder.getHandle()));
                holder.getModule().getLogger().info("start bukkitTimer:" + config.toString());
            }
        });
        InitialStageCallbackContext.registerCallback(ModuleContext.rootModuleId, PostLoad.class, callback);
    }

    public static boolean isPluginRegister() {
        return pluginRegister;
    }

    public static void setPluginRegister(boolean pluginRegister) {
        InitialStageCallbackRegister.pluginRegister = pluginRegister;
    }

}
